home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 4
/
Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso
/
Pearls
/
dev
/
Oberon
/
OberonV4
/
system
/
Sessions.Mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1996-03-03
|
18KB
|
434 lines
Syntax10.Scn.Fnt
Syntax10i.Scn.Fnt
StampElems
Alloc
3 Mar 96
FoldElems
Syntax10.Scn.Fnt
TCP,
Syntax10.Scn.Fnt
(*V24*)
Syntax10.Scn.Fnt
NetSystem,
Syntax10b.Scn.Fnt
Syntax10.Scn.Fnt
TCPConnection = POINTER TO RECORD(TCP.ConnectionDesc) channel: Channel END;
TCPChannel = POINTER TO RECORD(ChannelDesc) connection: TCPConnection END;
TCPTask = POINTER TO RECORD(TaskDesc) id: LONGINT END;
TCPListener = POINTER TO RECORD(ListenerDesc) l: TCP.Listener END;
Syntax10.Scn.Fnt
NSConnection = POINTER TO RECORD(NetSystem.StreamDesc) channel: Channel END;
NSChannel = POINTER TO RECORD(ChannelDesc) connection: NSConnection END;
NSTask = POINTER TO RECORD(TaskDesc) c: NSConnection END;
NSListener = POINTER TO RECORD(ListenerDesc) l: NetSystem.Connection END;
Syntax10.Scn.Fnt
(*V24*)
Syntax10.Scn.Fnt
PROCEDURE TCPGetState(c: Channel; VAR available: LONGINT; VAR terminated: BOOLEAN);
VAR connection: TCP.Connection;
BEGIN connection := c(TCPChannel).connection;
available := TCP.Available(connection); terminated := (available = 0) & ~TCP.Connected(connection)
END TCPGetState;
PROCEDURE TCPReadBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
BEGIN TCP.ReadBytes(c(TCPChannel).connection, bytes, 0, n)
END TCPReadBytes;
PROCEDURE TCPSendBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
VAR connection: TCP.Connection;
BEGIN connection := c(TCPChannel).connection;
IF TCP.Connected(connection) THEN TCP.WriteBytes(connection, bytes, 0, n) END
END TCPSendBytes;
PROCEDURE TCPSendBreak(c: Channel);
END TCPSendBreak;
PROCEDURE TCPClose(c: Channel);
VAR connection: TCP.Connection;
BEGIN connection := c(TCPChannel).connection;
IF TCP.Connected(connection) THEN TCP.Disconnect(connection) END
END TCPClose;
PROCEDURE TCPSelfChannel(t: Task): Channel;
VAR channel: Channel; c: TCP.Connection;
BEGIN c := TCP.ThisConnection(t(TCPTask).id);
IF c # NIL THEN channel := c(TCPConnection).channel ELSE channel := NIL END;
RETURN channel
END TCPSelfChannel;
PROCEDURE TCPSetupChannel(connection: TCPConnection; VAR channel: Channel; VAR task: Task);
VAR c: TCPChannel; t: TCPTask;
BEGIN NEW(c); c.connection := connection; connection.channel := c;
c.getState := TCPGetState; c.readBytes := TCPReadBytes;
c.sendBytes := TCPSendBytes; c.sendBreak := TCPSendBreak; c.close := TCPClose;
NEW(t); t.id := connection.id; t.channel := TCPSelfChannel;
channel := c; task := t
END TCPSetupChannel;
PROCEDURE TCPNewSession(hostname: ARRAY OF CHAR; port: LONGINT): Session;
VAR res: INTEGER; c: TCPConnection; channel: Channel; t: Task; s: Session; adr: TCP.IpAdr;
BEGIN s := NIL; TCP.HostByName(hostname, adr, res);
IF res = TCP.Done THEN NEW(c); TCP.Connect(c, TCP.AnyPort, adr, SHORT(port), 0, res);
IF res = TCP.Done THEN TCPSetupChannel(c, channel, t); s := NewSession(channel, t, hostname) END
END;
RETURN s
END TCPNewSession;
PROCEDURE TCPRequested(l: Listener): BOOLEAN;
BEGIN RETURN TCP.Requested(l(TCPListener).l)
END TCPRequested;
PROCEDURE TCPAcceptedSession(l: Listener; VAR serverName: ARRAY OF CHAR): Session;
VAR res: INTEGER; c: TCPConnection; channel: Channel; t: Task; s: Session;
BEGIN s := NIL;
NEW(c); TCP.Accept(l(TCPListener).l, c, res);
IF res = TCP.Done THEN TCPSetupChannel(c, channel, t); s := NewSession(channel, t, serverName) END;
RETURN s
END TCPAcceptedSession;
PROCEDURE TCPRemove(l: Listener);
BEGIN TCP.Close(l(TCPListener).l)
END TCPRemove;
PROCEDURE TCPNewListener(port: LONGINT): TCPListener;
VAR res: INTEGER; listener: TCPListener; l: TCP.Listener;
BEGIN listener := NIL;
NEW(l); TCP.Listen(l, SHORT(port), TCP.AnyAdr, TCP.AnyPort, res);
IF res = TCP.Done THEN NEW(listener); listener.l := l;
listener.requested := TCPRequested; listener.acceptedSession := TCPAcceptedSession;
listener.remove := TCPRemove
END;
RETURN listener
END TCPNewListener;
Syntax10.Scn.Fnt
(*V24*)
Syntax10.Scn.Fnt
PROCEDURE NSGetState(c: Channel; VAR available: LONGINT; VAR terminated: BOOLEAN);
VAR connection: NetSystem.Stream;
BEGIN connection := c(NSChannel).connection;
available := NetSystem.Available(connection);
terminated := (available = 0) & (connection.C.state = NetSystem.closed)
END NSGetState;
PROCEDURE NSReadBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
BEGIN NetSystem.ReadBytes(c(NSChannel).connection, bytes, 0, n)
END NSReadBytes;
PROCEDURE NSSendBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
VAR connection: NetSystem.Stream;
BEGIN connection := c(NSChannel).connection;
IF connection.C.state # NetSystem.closed THEN NetSystem.WriteBytes(connection, bytes, 0, n) END
END NSSendBytes;
PROCEDURE NSSendBreak(c: Channel);
END NSSendBreak;
PROCEDURE NSClose(c: Channel);
VAR connection: NetSystem.Stream;
BEGIN connection := c(NSChannel).connection;
IF connection.C.state # NetSystem.closed THEN NetSystem.CloseConnection(connection.C) END
END NSClose;
PROCEDURE NSSelfChannel(t: Task): Channel;
BEGIN RETURN t(NSTask).c.channel
END NSSelfChannel;
PROCEDURE NSSetupChannel(connection: NSConnection; VAR channel: Channel; VAR task: Task);
VAR c: NSChannel; t: NSTask;
BEGIN NEW(c); c.connection := connection; connection.channel := c;
c.getState := NSGetState; c.readBytes := NSReadBytes;
c.sendBytes := NSSendBytes; c.sendBreak := NSSendBreak; c.close := NSClose;
NEW(t); t.c := connection; t.channel := NSSelfChannel;
channel := c; task := t
END NSSetupChannel;
PROCEDURE NSNewSession(hostname: ARRAY OF CHAR; port: LONGINT): Session;
VAR res: INTEGER; connection: NSConnection; channel: Channel; t: Task; s: Session; c: NetSystem.Connection;
BEGIN s := NIL;
NEW(c); NetSystem.OpenConnection(NetSystem.anyport, SHORT(port), hostname, NetSystem.tcp, c, res);
IF res = NetSystem.done THEN
NEW(connection); NetSystem.OpenStream(connection, c);
NSSetupChannel(connection, channel, t); s := NewSession(channel, t, hostname)
END;
RETURN s
END NSNewSession;
PROCEDURE NSRequested(l: Listener): BOOLEAN;
BEGIN RETURN NetSystem.Requested(l(NSListener).l)
END NSRequested;
PROCEDURE NSAcceptedSession(l: Listener; VAR serverName: ARRAY OF CHAR): Session;
VAR res: INTEGER; c: NSConnection; channel: Channel; t: Task; s: Session; connection: NetSystem.Connection;
BEGIN s := NIL;
NEW(c); NetSystem.Accept(l(NSListener).l, connection, res);
IF res = NetSystem.done THEN
NetSystem.OpenStream(c, connection);
NSSetupChannel(c, channel, t); s := NewSession(channel, t, serverName) END;
RETURN s
END NSAcceptedSession;
PROCEDURE NSRemove(l: Listener);
BEGIN NetSystem.CloseConnection(l(NSListener).l)
END NSRemove;
PROCEDURE NSNewListener(port: LONGINT): NSListener;
VAR res: INTEGER; listener: NSListener; l: NetSystem.Connection;
BEGIN listener := NIL;
NEW(l);
NetSystem.OpenConnection(SHORT(port), NetSystem.anyport, NetSystem.anyIP, NetSystem.tcp, l, res);
IF res = NetSystem.done THEN NEW(listener); listener.l := l;
listener.requested := NSRequested; listener.acceptedSession := NSAcceptedSession;
listener.remove := NSRemove
END;
RETURN listener
END NSNewListener;
Syntax10.Scn.Fnt
(*V24*)
Syntax10.Scn.Fnt
s := TCPNewSession(hostname, port)
Syntax10.Scn.Fnt
s := NSNewSession(hostname, port)
Syntax10.Scn.Fnt
l := TCPNewListener(port);
IF l # NIL THEN ok := TRUE; s.listener := l; s.notify := c END
Syntax10.Scn.Fnt
l := NSNewListener(port);
IF l # NIL THEN ok := TRUE; s.listener := l; s.notify := c END
Syntax10.Scn.Fnt
(*V24*)
MODULE Sessions; (* ww
IMPORT
(*TCP*)
V24,
(*NetSystem*)
Oberon, Texts, Viewers, Display;
CONST
Sec* = 300;
TYPE
Channel = POINTER TO ChannelDesc;
Terminal* = POINTER TO TerminalDesc;
Session* = POINTER TO SessionDesc;
SessionDesc = RECORD
name: ARRAY 64 OF CHAR;
terminals, p: Terminal;
nomoreneeded: BOOLEAN;
channel: Channel
END;
ChannelDesc = RECORD
getState: PROCEDURE (c: Channel; VAR available: LONGINT; VAR terminated: BOOLEAN);
readBytes: PROCEDURE (c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
sendBytes: PROCEDURE (c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
sendBreak: PROCEDURE (c: Channel);
close: PROCEDURE (c: Channel);
session: Session
END;
Task = POINTER TO TaskDesc;
TaskDesc = RECORD(Oberon.TaskDesc)
channel: PROCEDURE (self: Task): Channel
END;
Receiver* = PROCEDURE (t: Terminal; ch: CHAR);
Flusher* = PROCEDURE (t: Terminal; changed, terminated: BOOLEAN);
TerminalDesc* = RECORD
next: Terminal;
session: Session;
nextTime, timeout*: LONGINT;
receive*: Receiver;
flush*: Flusher;
safe*: BOOLEAN
END;
Sentinel = POINTER TO RECORD(TerminalDesc) END;
Tester* = PROCEDURE (t: Terminal): BOOLEAN;
IdentifyMsg* = RECORD(Display.FrameMsg) session*: Session END;
Listener = POINTER TO ListenerDesc;
Service* = POINTER TO ServiceDesc;
ServiceCall* = PROCEDURE (this: Service; s: Session);
ServiceDesc* = RECORD
name: ARRAY 64 OF CHAR;
notify: ServiceCall;
listener: Listener
END;
ListenerDesc = RECORD
requested: PROCEDURE (l: Listener): BOOLEAN;
acceptedSession: PROCEDURE (l: Listener; VAR serverName: ARRAY OF CHAR): Session;
remove: PROCEDURE (l: Listener)
END;
ServiceTask = POINTER TO RECORD(Oberon.TaskDesc) service: Service END;
(*TCP*)
(*NetSystem*)
v24Session: Session;
PROCEDURE Distribute(s: Session; ch: CHAR);
VAR t: Terminal;
BEGIN s.p := s.terminals; t := s.p.next;
WHILE ~(t IS Sentinel) DO
IF ~t.safe THEN s.p.next := t.next; t.next := NIL END;
t.receive(t, ch);
IF (t.session = s) & (t.next = NIL) THEN t.next := s.p.next; s.p.next := t; s.p := t
ELSIF s.p.next = t THEN s.p := t
END;
t := s.p.next
END
END Distribute;
PROCEDURE Flush(s: Session; changed, terminated: BOOLEAN);
VAR t: Terminal; now: LONGINT;
BEGIN now := Oberon.Time(); s.p := s.terminals; t := s.p.next;
WHILE ~(t IS Sentinel) DO
IF changed OR terminated OR (t.nextTime <= now) & (t.timeout >= 0) THEN
IF ~t.safe THEN s.p.next := t.next; t.next := NIL END;
t.flush(t, changed, terminated); t.nextTime := now + t.timeout;
IF (t.session = s) & (t.next = NIL) THEN t.next := s.p.next; s.p.next := t; s.p := t
ELSIF s.p.next = t THEN s.p := t
END
ELSE s.p := t
END;
t := s.p.next
END
END Flush;
PROCEDURE Close*(s: Session);
VAR c: Channel;
BEGIN c := s.channel;
IF c.close # NIL THEN c.close(c) END
END Close;
PROCEDURE TaskHandler;
CONST BufSize = 4096;
VAR n, i: LONGINT; terminated: BOOLEAN; s: Session; c: Channel; self: Task; buf: ARRAY BufSize OF CHAR;
BEGIN self := Oberon.CurTask(Task); c := self.channel(self);
IF c # NIL THEN s := c.session; c.getState(c, n, terminated);
IF n # 0 THEN
IF n > BufSize THEN n := BufSize END;
c.readBytes(c, buf, n);
i := 0;
REPEAT Distribute(s, buf[i]); INC(i) UNTIL i = n
END;
Flush(s, n # 0, terminated);
IF terminated THEN Close(s); Oberon.Remove(Oberon.CurTask) END
ELSE Oberon.Remove(Oberon.CurTask)
END
END TaskHandler;
PROCEDURE NewSession(c: Channel; task: Task; VAR name: ARRAY OF CHAR): Session;
VAR s: Session; sentinel: Sentinel;
BEGIN NEW(s); COPY(name, s.name);
s.channel := c; c.session := s;
NEW(sentinel); s.terminals := sentinel; sentinel.session := s; sentinel.next := sentinel;
task.handle := TaskHandler; task.safe := TRUE; task.time := -1;
Oberon.Install(task);
RETURN s
END NewSession;
PROCEDURE Install*(t: Terminal; s: Session; r: Receiver; f: Flusher; timeout: LONGINT);
VAR sentinel: Terminal;
BEGIN ASSERT(t.session = NIL);
t.session := s; sentinel := s.terminals; t.next := sentinel.next; sentinel.next := t;
IF s.p = s.terminals THEN s.p := t END;
t.receive := r; t.flush := f; t.timeout := timeout; t.nextTime := Oberon.Time() + timeout
END Install;
PROCEDURE Remove*(t: Terminal);
VAR p, q: Terminal; s: Session;
BEGIN s := t.session;
IF s # NIL THEN p := s.terminals; q := p.next;
WHILE (q # t) & ~(q IS Sentinel) DO p := q; q := q.next END;
IF q = t THEN p.next := t.next;
IF q = s.p THEN s.p := p END
END;
t.session := NIL; t.next := NIL;
p := s.terminals;
IF p.next = p THEN Close(s) END
END
END Remove;
PROCEDURE ThisSession*(t: Terminal): Session;
BEGIN RETURN t.session
END ThisSession;
PROCEDURE ThisTerminal*(s: Session; test: Tester): Terminal;
VAR t: Terminal;
BEGIN t := s.terminals.next;
WHILE ~(t IS Sentinel) & ~test(t) DO t := t.next END;
IF t IS Sentinel THEN RETURN NIL ELSE RETURN t END
END ThisTerminal;
PROCEDURE GetName*(s: Session; VAR name: ARRAY OF CHAR);
BEGIN COPY(s.name, name)
END GetName;
PROCEDURE SendChar*(s: Session; ch: CHAR);
VAR c: Channel; buf: ARRAY 1 OF CHAR;
BEGIN c := s.channel; buf[0] := ch; c.sendBytes(c, buf, 1)
END SendChar;
PROCEDURE SendBytes*(s: Session; VAR bytes: ARRAY OF CHAR; n: LONGINT);
VAR c: Channel;
BEGIN c := s.channel; c.sendBytes(c, bytes, n)
END SendBytes;
PROCEDURE SendString*(s: Session; str: ARRAY OF CHAR);
VAR i: LONGINT; c: Channel;
BEGIN i := 0;
WHILE str[i] # 0X DO INC(i) END;
c := s.channel; c.sendBytes(c, str, i)
END SendString;
PROCEDURE SendBreak*(s: Session);
VAR c: Channel;
BEGIN c := s.channel; c.sendBreak(c)
END SendBreak;
(*TCP*)
PROCEDURE V24GetState(c: Channel; VAR available: LONGINT; VAR terminated: BOOLEAN);
BEGIN available := V24.Available(); terminated := FALSE
END V24GetState;
PROCEDURE V24ReadBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
VAR i: LONGINT;
BEGIN i := 0;
WHILE i # n DO V24.Receive(bytes[i]); INC(i) END
END V24ReadBytes;
PROCEDURE V24SendBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
VAR i: LONGINT;
BEGIN i := 0;
WHILE i # n DO V24.Send(bytes[i]); INC(i) END
END V24SendBytes;
PROCEDURE V24SendBreak(c: Channel);
BEGIN V24.Break
END V24SendBreak;
PROCEDURE V24SelfChannel(self: Task): Channel;
BEGIN RETURN v24Session.channel
END V24SelfChannel;
PROCEDURE V24NewSession(): Session;
VAR c: Channel; task: Task; name: ARRAY 4 OF CHAR;
BEGIN NEW(c); c.getState := V24GetState; c.readBytes := V24ReadBytes;
c.sendBytes := V24SendBytes; c.sendBreak := V24SendBreak;
NEW(task); task.channel := V24SelfChannel;
name := "V24"; RETURN NewSession(c, task, name)
END V24NewSession;
(*NetSystem*)
PROCEDURE New*(hostname: ARRAY OF CHAR; port: LONGINT): Session;
VAR s: Session;
BEGIN s := NIL;
IF hostname = "V24" THEN
s := v24Session
ELSE
(*TCP*)
(*NetSystem*)
END;
RETURN s
END New;
PROCEDURE ServiceTaskHandler;
VAR serv: Service; l: Listener; s: Session;
BEGIN serv := Oberon.CurTask(ServiceTask).service; l := serv.listener;
IF l # NIL THEN
IF l.requested(l) THEN s := l.acceptedSession(l, serv.name);
IF s # NIL THEN serv.notify(serv, s) END
END
ELSE Oberon.Remove(Oberon.CurTask)
END
END ServiceTaskHandler;
PROCEDURE InstallService*(s: Service; port: LONGINT; c: ServiceCall; name: ARRAY OF CHAR; VAR ok: BOOLEAN);
VAR l: Listener; task: ServiceTask;
BEGIN ok := FALSE;
IF s.listener = NIL THEN
IF name = "V24" THEN
ELSE
(*TCP*)
(*NetSystem*)
END
END;
IF ok THEN NEW(task); task.handle := ServiceTaskHandler; task.time := -1; task.service := s;
Oberon.Install(task); COPY(name, s.name)
END
END InstallService;
PROCEDURE RemoveService*(s: Service);
VAR l: Listener;
BEGIN l := s.listener; l.remove(l); s.listener := NIL
END RemoveService;
PROCEDURE Send*;
VAR text: Texts.Text; beg, end, time: LONGINT; v: Viewers.Viewer; s: Texts.Scanner; identify: IdentifyMsg;
BEGIN
IF Oberon.Par.vwr.dsc = Oberon.Par.frame THEN v := Oberon.Par.vwr ELSE v := Oberon.FocusViewer END;
identify.session := NIL; v.handle(v, identify);
IF identify.session # NIL THEN
Texts.OpenScanner(s, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(s);
IF (s.class = Texts.Char) & (s.line = 0) & (s.c = "^") THEN Oberon.GetSelection(text, beg, end, time);
IF time > 0 THEN Texts.OpenScanner(s, text, beg); Texts.Scan(s) END
END;
LOOP
IF (s.class = Texts.Name) & (s.s = "BRK") THEN SendBreak(identify.session)
ELSIF (s.class = Texts.Name) OR (s.class = Texts.String) THEN SendString(identify.session, s.s)
ELSIF s.class = Texts.Int THEN SendChar(identify.session, CHR(s.i MOD 256))
ELSE EXIT
END;
Texts.Scan(s)
END
END
END Send;
BEGIN
v24Session := V24NewSession()
END Sessions.